#include <cmath>
#include <sys/time.h>
#include "timer.h"

#define iabs(a) ((a) < 0 ? -(a) : (a))
#define imax(a,b) ((a) > (b) ? (a) : (b))

Timer::Timer() {
	mOperaciones = 0;
	mOperacionesLog = 0.0;
	mClockInicial = mClockFinal = 0;
	mTiempoInicial.tv_sec = mTiempoFinal.tv_sec = 0;
	mTiempoInicial.tv_usec = mTiempoFinal.tv_usec = 0;
}

void Timer::comenzar() {
	gettimeofday ( &mTiempoInicial, 0 );
	mClockInicial = rdtsc();
	mOperaciones = 0;
	mOperacionesLog = 0.0;
}

void Timer::terminar() {
	gettimeofday ( &mTiempoFinal, 0 );
	mClockFinal = rdtsc();
}

resultado_t Timer::getTiempo () const {
	resultado_t segundos, microsegs;
	segundos = static_cast<resultado_t>(mTiempoFinal.tv_sec - mTiempoInicial.tv_sec);
	microsegs = static_cast<resultado_t>(mTiempoFinal.tv_usec - mTiempoInicial.tv_usec);
	return segundos * 1000000 + microsegs;
}

long double Timer::getMilisegundos() const {
	return static_cast<long double>(getTiempo()) / 1000.0;
}

long double Timer::getSegundos() const {
	return static_cast<long double>(getTiempo()) / 1000000.0;
}


void Timer::opSencilla( int a, int b ) {
	a = iabs(a);
	b = iabs(b);
	
	a = a ? a : 1;
	b = b ? b : 1;
	
	mOperacionesLog += std::log( a ) + std::log( b );
	mOperaciones++;
}

void Timer::opComplicada ( int a, int b ) {
	a = iabs(a);
	b = iabs(b);
	
	a = a ? a : 1;
	b = b ? b : 1;
	
	mOperacionesLog += (std::log( a ) / std::log( 2 )) * (std::log( b ) / std::log( 2 ));
	mOperaciones++;
}

void Timer::opRaiz ( int n ) {
	double nro = static_cast<double>( iabs(n) );
	double res;
	
	if( nro < 0 )
		res = 1;
	else
		res = std::log(nro);

	mOperaciones++;
	mOperacionesLog += res * res;
}

uint64_t Timer::rdtsc() {
	uint32_t eax, edx;
	__asm__ __volatile__ ( "rdtsc" : "=a"(eax), "=d"(edx) );
	return static_cast<uint64_t>(eax) + (static_cast<uint64_t>(edx) << 32);
}
